import logging
from typing import Dict, Any
from datetime import datetime
from sqlalchemy.orm import Session
from sqlalchemy import create_engine

from app.core.config.settings import settings
from app.core.mqtt.client import mqtt_manager
from app.domains.models import Device, Alert, SensorData, WorkOrder
from app.shared.constants.enums import DeviceStatus, AlertLevel, AlertType, WorkOrderType, WorkOrderPriority
from app.shared.utils.datetime import utc_now
from app.shared.exceptions.base import BusinessException
from app.shared.constants.status_codes import BusinessCode

logger = logging.getLogger(__name__)


class DeviceMQTTService:
    """设备MQTT消息处理服务"""
    
    def __init__(self):
        self.engine = create_engine(settings.DATABASE_URL)
    
    def get_db_session(self) -> Session:
        """获取数据库会话"""
        return Session(bind=self.engine)
    
    async def setup_handlers(self):
        """设置MQTT消息处理器"""
        mqtt_manager.register_handler("status", self.handle_device_status)
        mqtt_manager.register_handler("sensor", self.handle_sensor_data)
        mqtt_manager.register_handler("alert", self.handle_device_alert)
        mqtt_manager.register_handler("emergency", self.handle_emergency)
        mqtt_manager.register_handler("heartbeat", self.handle_heartbeat)
        mqtt_manager.register_handler("location", self.handle_location_update)
        mqtt_manager.register_handler("usage", self.handle_usage_statistics)
        
        logger.info("📡 MQTT消息处理器设置完成")
    
    async def handle_device_status(self, message_data: Dict[str, Any]):
        """处理设备状态更新"""
        try:
            device_id = message_data['device_id']
            location = message_data['location']
            payload = message_data['payload']
            
            logger.info(f"📊 处理设备状态更新: {device_id}")
            
            db = self.get_db_session()
            try:
                # 查找设备
                device = db.query(Device).filter(Device.device_code == device_id).first()
                if not device:
                    logger.warning(f"⚠️  设备不存在: {device_id}")
                    await self._create_unknown_device(device_id, location, db)
                    return
                
                # 更新设备状态
                status_data = payload.get('status', {})
                
                # 更新基本状态
                if 'online' in status_data:
                    device.status = DeviceStatus.ONLINE if status_data['online'] else DeviceStatus.OFFLINE
                
                # 更新传感器数据
                sensors = payload.get('sensors', {})
                if sensors:
                    await self._update_device_sensors(device, sensors, db)
                
                # 更新位置信息
                location_data = payload.get('location', {})
                if location_data:
                    if 'latitude' in location_data:
                        device.latitude = location_data['latitude']
                    if 'longitude' in location_data:
                        device.longitude = location_data['longitude']
                
                # 更新最后在线时间
                device.last_seen_at = utc_now()
                device.updated_at = utc_now()
                
                db.commit()
                logger.info(f"✅ 设备状态更新成功: {device_id}")
                
                # 检查是否需要触发告警
                await self._check_device_alerts(device, sensors, db)
                
            finally:
                db.close()
                
        except Exception as e:
            logger.error(f"❌ 处理设备状态失败: {e}, 设备: {message_data.get('device_id')}")
    
    async def handle_sensor_data(self, message_data: Dict[str, Any]):
        """处理传感器数据"""
        try:
            device_id = message_data['device_id']
            payload = message_data['payload']
            timestamp_str = payload.get('timestamp')
            
            logger.debug(f"📡 处理传感器数据: {device_id}")
            
            db = self.get_db_session()
            try:
                # 查找设备
                device = db.query(Device).filter(Device.device_code == device_id).first()
                if not device:
                    logger.warning(f"⚠️  设备不存在: {device_id}")
                    return
                
                # 解析时间戳
                try:
                    if timestamp_str:
                        timestamp = datetime.fromisoformat(timestamp_str.replace('Z', '+00:00'))
                    else:
                        timestamp = utc_now()
                except ValueError:
                    timestamp = utc_now()
                
                # 保存传感器数据
                sensors = payload.get('sensors', {})
                for sensor_type, value in sensors.items():
                    if isinstance(value, (int, float)):
                        sensor_data = SensorData(
                            device_id=device.id,
                            timestamp=timestamp,
                            data_type=sensor_type,
                            value=float(value),
                            unit=self._get_sensor_unit(sensor_type),
                            quality=payload.get('quality', 100),
                            created_at=utc_now()
                        )
                        db.add(sensor_data)
                
                # 更新设备耗材余量
                if 'paper_level' in sensors:
                    device.materials_level = sensors['paper_level']
                
                # 更新最后在线时间
                device.last_seen_at = timestamp
                device.updated_at = utc_now()
                
                db.commit()
                logger.debug(f"✅ 传感器数据保存成功: {device_id}")
                
                # 检查传感器阈值告警
                await self._check_sensor_alerts(device, sensors, db)
                
            finally:
                db.close()
                
        except Exception as e:
            logger.error(f"❌ 处理传感器数据失败: {e}, 设备: {message_data.get('device_id')}")
    
    async def handle_device_alert(self, message_data: Dict[str, Any]):
        """处理设备告警"""
        try:
            device_id = message_data['device_id']
            payload = message_data['payload']
            
            logger.warning(f"🚨 处理设备告警: {device_id} - {payload.get('alert_type')}")
            
            db = self.get_db_session()
            try:
                # 查找设备
                device = db.query(Device).filter(Device.device_code == device_id).first()
                if not device:
                    logger.warning(f"⚠️  设备不存在: {device_id}")
                    return
                
                # 创建告警记录
                alert = Alert(
                    device_id=device.id,
                    alert_type=AlertType(payload.get('alert_type', 'fault')),
                    level=AlertLevel(payload.get('severity', 'warning')),
                    title=payload.get('message', '设备告警'),
                    message=payload.get('message'),
                    data=payload.get('data', {}),
                    auto_resolved=False,
                    created_at=utc_now()
                )
                
                db.add(alert)
                
                # 如果是故障告警，更新设备状态
                if payload.get('alert_type') == 'fault':
                    device.status = DeviceStatus.FAULT
                    device.updated_at = utc_now()
                
                db.commit()
                logger.info(f"✅ 设备告警创建成功: {device_id} - {alert.id}")
                
                # 发送告警通知
                await self._send_alert_notification(alert, device)
                
            finally:
                db.close()
                
        except Exception as e:
            logger.error(f"❌ 处理设备告警失败: {e}, 设备: {message_data.get('device_id')}")
    
    async def handle_emergency(self, message_data: Dict[str, Any]):
        """处理紧急情况"""
        try:
            device_id = message_data['device_id']
            payload = message_data['payload']
            
            logger.critical(f"🆘 处理紧急情况: {device_id} - {payload.get('message', '未知紧急情况')}")
            
            db = self.get_db_session()
            try:
                # 查找设备
                device = db.query(Device).filter(Device.device_code == device_id).first()
                if not device:
                    logger.warning(f"⚠️  设备不存在: {device_id}")
                    return
                
                # 创建严重告警
                alert = Alert(
                    device_id=device.id,
                    alert_type=AlertType.FAULT,
                    level=AlertLevel.CRITICAL,
                    title="紧急情况",
                    message=payload.get('message', '设备紧急情况'),
                    data=payload,
                    auto_resolved=False,
                    created_at=utc_now()
                )
                
                db.add(alert)
                
                # 自动创建紧急工单
                work_order = WorkOrder(
                    order_number=self._generate_order_number(),
                    device_id=device.id,
                    creator_id=1,  # 系统用户
                    title="紧急故障处理",
                    description=f"设备紧急情况: {payload.get('message', '未知情况')}",
                    priority=WorkOrderPriority.URGENT,
                    work_type=WorkOrderType.REPAIR,
                    created_at=utc_now()
                )
                
                db.add(work_order)
                
                # 更新设备状态
                device.status = DeviceStatus.FAULT
                device.updated_at = utc_now()
                
                db.commit()
                
                logger.critical(f"🆘 紧急情况处理完成: 告警ID={alert.id}, 工单ID={work_order.id}")
                
                # 发送紧急通知
                await self._send_emergency_notification(alert, work_order, device)
                
            finally:
                db.close()
                
        except Exception as e:
            logger.error(f"❌ 处理紧急情况失败: {e}, 设备: {message_data.get('device_id')}")
    
    async def handle_heartbeat(self, message_data: Dict[str, Any]):
        """处理设备心跳"""
        try:
            device_id = message_data['device_id']
            
            logger.debug(f"💓 处理设备心跳: {device_id}")
            
            db = self.get_db_session()
            try:
                # 更新设备最后在线时间
                device = db.query(Device).filter(Device.device_code == device_id).first()
                if device:
                    device.last_seen_at = utc_now()
                    # 如果设备之前是离线状态，现在收到心跳，更新为在线
                    if device.status == DeviceStatus.OFFLINE:
                        device.status = DeviceStatus.ONLINE
                        logger.info(f"📶 设备重新上线: {device_id}")
                    
                    device.updated_at = utc_now()
                    db.commit()
                
            finally:
                db.close()
                
        except Exception as e:
            logger.error(f"❌ 处理设备心跳失败: {e}, 设备: {message_data.get('device_id')}")
    
    async def handle_location_update(self, message_data: Dict[str, Any]):
        """处理位置更新"""
        try:
            device_id = message_data['device_id']
            payload = message_data['payload']
            
            logger.debug(f"📍 处理位置更新: {device_id}")
            
            db = self.get_db_session()
            try:
                device = db.query(Device).filter(Device.device_code == device_id).first()
                if device:
                    location = payload.get('location', {})
                    if 'latitude' in location and 'longitude' in location:
                        device.latitude = location['latitude']
                        device.longitude = location['longitude']
                        device.updated_at = utc_now()
                        db.commit()
                        logger.debug(f"✅ 设备位置更新成功: {device_id}")
                
            finally:
                db.close()
                
        except Exception as e:
            logger.error(f"❌ 处理位置更新失败: {e}, 设备: {message_data.get('device_id')}")
    
    async def handle_usage_statistics(self, message_data: Dict[str, Any]):
        """处理使用统计"""
        try:
            device_id = message_data['device_id']
            payload = message_data['payload']
            
            logger.debug(f"📈 处理使用统计: {device_id}")
            
            # TODO: 实现使用统计数据处理
            # 可以保存到 DeviceStatistics 表中
            
        except Exception as e:
            logger.error(f"❌ 处理使用统计失败: {e}, 设备: {message_data.get('device_id')}")
    
    def _get_sensor_unit(self, sensor_type: str) -> str:
        """获取传感器单位"""
        unit_mapping = {
            'temperature': '°C',
            'humidity': '%',
            'water_level': '%',
            'waste_level': '%',
            'paper_level': '%',
            'soap_level': '%',
            'battery_level': '%',
        }
        return unit_mapping.get(sensor_type, '')
    
    async def _update_device_sensors(self, device: Device, sensors: Dict[str, Any], db: Session):
        """更新设备传感器数据"""
        # 更新设备状态相关的传感器数据
        if 'paper_level' in sensors:
            device.materials_level = sensors['paper_level']
        
        # 可以根据需要添加其他传感器数据的处理逻辑
    
    async def _check_device_alerts(self, device: Device, sensors: Dict[str, Any], db: Session):
        """检查设备告警条件"""
        alerts_to_create = []
        
        # 检查各种传感器阈值
        if sensors.get('paper_level', 100) < settings.PAPER_LOW_THRESHOLD:
            alerts_to_create.append({
                'type': AlertType.LOW_MATERIALS,
                'level': AlertLevel.WARNING,
                'title': '纸巾余量不足',
                'message': f'设备 {device.device_name} 纸巾余量仅剩 {sensors.get("paper_level")}%',
                'data': {'paper_level': sensors.get('paper_level'), 'threshold': settings.PAPER_LOW_THRESHOLD}
            })
        
        if sensors.get('soap_level', 100) < settings.SOAP_LOW_THRESHOLD:
            alerts_to_create.append({
                'type': AlertType.LOW_MATERIALS,
                'level': AlertLevel.WARNING,
                'title': '洗手液余量不足',
                'message': f'设备 {device.device_name} 洗手液余量仅剩 {sensors.get("soap_level")}%',
                'data': {'soap_level': sensors.get('soap_level'), 'threshold': settings.SOAP_LOW_THRESHOLD}
            })
        
        if sensors.get('waste_level', 0) > settings.WASTE_HIGH_THRESHOLD:
            alerts_to_create.append({
                'type': AlertType.LOW_MATERIALS,
                'level': AlertLevel.ERROR,
                'title': '污物箱即将满载',
                'message': f'设备 {device.device_name} 污物箱容量已达 {sensors.get("waste_level")}%',
                'data': {'waste_level': sensors.get('waste_level'), 'threshold': settings.WASTE_HIGH_THRESHOLD}
            })
        
        if sensors.get('battery_level', 100) < settings.BATTERY_LOW_THRESHOLD:
            alerts_to_create.append({
                'type': AlertType.BATTERY_LOW,
                'level': AlertLevel.WARNING,
                'title': '电池电量不足',
                'message': f'设备 {device.device_name} 电池电量仅剩 {sensors.get("battery_level")}%',
                'data': {'battery_level': sensors.get('battery_level'), 'threshold': settings.BATTERY_LOW_THRESHOLD}
            })
        
        if sensors.get('temperature', 25) > settings.TEMPERATURE_HIGH_THRESHOLD:
            alerts_to_create.append({
                'type': AlertType.TEMPERATURE_HIGH,
                'level': AlertLevel.WARNING,
                'title': '设备温度过高',
                'message': f'设备 {device.device_name} 温度达到 {sensors.get("temperature")}°C',
                'data': {'temperature': sensors.get('temperature'), 'threshold': settings.TEMPERATURE_HIGH_THRESHOLD}
            })
        
        # 创建告警记录
        for alert_data in alerts_to_create:
            # 检查是否已有相同类型的未解决告警
            existing_alert = db.query(Alert).filter(
                Alert.device_id == device.id,
                Alert.alert_type == alert_data['type'],
                Alert.is_resolved == False
            ).first()
            
            if not existing_alert:
                alert = Alert(
                    device_id=device.id,
                    alert_type=alert_data['type'],
                    level=alert_data['level'],
                    title=alert_data['title'],
                    message=alert_data['message'],
                    data=alert_data['data'],
                    auto_resolved=False,
                    created_at=utc_now()
                )
                db.add(alert)
                logger.info(f"🚨 创建告警: {device.device_name} - {alert_data['title']}")
    
    async def _check_sensor_alerts(self, device: Device, sensors: Dict[str, Any], db: Session):
        """检查传感器告警"""
        # 调用设备告警检查
        await self._check_device_alerts(device, sensors, db)
    
    async def _create_unknown_device(self, device_id: str, location: str, db: Session):
        """创建未知设备记录"""
        try:
            device = Device(
                device_code=device_id,
                device_name=f"未知设备-{device_id}",
                device_type=DeviceType.PORTABLE_TOILET,
                location_name=location,
                status=DeviceStatus.ONLINE,
                created_at=utc_now()
            )
            db.add(device)
            db.commit()
            logger.info(f"📝 创建未知设备记录: {device_id}")
        except Exception as e:
            logger.error(f"❌ 创建未知设备失败: {e}")
    
    def _generate_order_number(self) -> str:
        """生成工单号"""
        from app.shared.utils.formatter import generate_order_number
        return generate_order_number()
    
    async def _send_alert_notification(self, alert: Alert, device: Device):
        """发送告警通知"""
        # TODO: 实现告警通知发送
        logger.info(f"📧 发送告警通知: {device.device_name} - {alert.title}")
    
    async def _send_emergency_notification(self, alert: Alert, work_order: WorkOrder, device: Device):
        """发送紧急通知"""
        # TODO: 实现紧急通知发送
        logger.critical(f"📧 发送紧急通知: {device.device_name} - {alert.title}")


# 全局设备MQTT服务实例
device_mqtt_service = DeviceMQTTService()